<!doctype html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=robots content="noodp"><meta http-equiv=x-ua-compatible content="IE=edge, chrome=1"><title>Java高并发秒杀API(三)之Web层 - Yulin Lewis' Blog</title><meta name=keywords content="雨临Lewis,Java,hugo,hexo,博客"><meta name=Description content="不想当写手的码农不是好咸鱼_(xз」∠)_"><meta property="og:title" content="Java高并发秒杀API(三)之Web层"><meta property="og:description" content="1. 设计前的分析

Web层内容相关


前端交互设计
Restful规范
SpringMVC"><meta property="og:type" content="article"><meta property="og:url" content="https://lewky.cn/posts/33818.html/"><meta property="og:image" content="https://lewky.cn/logo.png"><meta property="article:published_time" content="2017-10-05T18:03:54+08:00"><meta property="article:modified_time" content="2017-10-05T18:03:54+08:00"><meta name=twitter:card content="summary_large_image"><meta name=twitter:image content="https://lewky.cn/logo.png"><meta name=twitter:title content="Java高并发秒杀API(三)之Web层"><meta name=twitter:description content="1. 设计前的分析

Web层内容相关


前端交互设计
Restful规范
SpringMVC"><meta name=application-name content="雨临Lewis的博客"><meta name=apple-mobile-web-app-title content="雨临Lewis的博客"><meta name=theme-color content="#ffffff"><meta name=msapplication-TileColor content="#da532c"><link rel="shortcut icon" type=image/x-icon href=/favicon.ico><link rel=icon type=image/png sizes=32x32 href=/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=/favicon-16x16.png><link rel=apple-touch-icon sizes=180x180 href=/apple-touch-icon.png><link rel=mask-icon href=/safari-pinned-tab.svg color=#5bbad5><link rel=manifest href=/site.webmanifest><link rel=canonical href=https://lewky.cn/posts/33818.html/><link rel=prev href=https://lewky.cn/posts/18357.html/><link rel=next href=https://lewky.cn/posts/43941.html/><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.min.css><link rel=stylesheet href=/css/style.min.css><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.13.0/css/all.min.css><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/animate.css@3.7.2/animate.min.css><script type=application/ld+json>{"@context":"http://schema.org","@type":"BlogPosting","headline":"Java高并发秒杀API(三)之Web层","inLanguage":"","mainEntityOfPage":{"@type":"WebPage","@id":"https:\/\/lewky.cn\/posts\/33818.html\/"},"genre":"posts","keywords":"项目笔记, SSM实战项目, 秒杀","wordcount":5548,"url":"https:\/\/lewky.cn\/posts\/33818.html\/","datePublished":"2017-10-05T18:03:54+08:00","dateModified":"2017-10-05T18:03:54+08:00","license":"This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.","publisher":{"@type":"Organization","name":"雨临Lewis","logo":"https:\/\/lewky.cn\/images\/avatar.jpg"},"author":{"@type":"Person","name":"雨临Lewis"},"description":""}</script></head><body header-desktop=fixed header-mobile=auto><script type=text/javascript>(window.localStorage&&localStorage.getItem('theme')?localStorage.getItem('theme')==='dark':('auto'==='auto'?window.matchMedia('(prefers-color-scheme: dark)').matches:'auto'==='dark'))&&document.body.setAttribute('theme','dark');</script><div id=mask></div><div class=wrapper><header class=desktop id=header-desktop><div class=header-wrapper><a href=https://github.com/lewky class=github-corner target=_blank title="Follow me on GitHub" aria-label="Follow me on GitHub"><svg width="3.5rem" height="3.5rem" viewBox="0 0 250 250" style="fill:#70b7fd;color:#fff;position:absolute;top:0;border:0;left:0;transform:scale(-1,1)" aria-hidden="true"><path d="M0 0 115 115h15l12 27L250 250V0z"/><path d="M128.3 109C113.8 99.7 119 89.6 119 89.6 122 82.7 120.5 78.6 120.5 78.6 119.2 72 123.4 76.3 123.4 76.3 127.3 80.9 125.5 87.3 125.5 87.3 122.9 97.6 130.6 101.9 134.4 103.2" fill="currentcolor" style="transform-origin:130px 106px" class="octo-arm"/><path d="M115 115C114.9 115.1 118.7 116.5 119.8 115.4L133.7 101.6C136.9 99.2 139.9 98.4 142.2 98.6 133.8 88 127.5 74.4 143.8 58 148.5 53.4 154 51.2 159.7 51 160.3 49.4 163.2 43.6 171.4 40.1 171.4 40.1 176.1 42.5 178.8 56.2 183.1 58.6 187.2 61.8 190.9 65.4 194.5 69 197.7 73.2 200.1 77.6 213.8 80.2 216.3 84.9 216.3 84.9 212.7 93.1 206.9 96 205.4 96.6 205.1 102.4 203 107.8 198.3 112.5 181.9 128.9 168.3 122.5 157.7 114.1 157.9 116.9 156.7 120.9 152.7 124.9L141 136.5C139.8 137.7 141.6 141.9 141.8 141.8z" fill="currentcolor" class="octo-body"/></svg></a><div class=header-title><a href=/ title="Yulin Lewis' Blog"><span class=header-title-pre><i class="fas fa-fw fa-atom"></i></span>雨临Lewis</a></div><div class=menu><div class=menu-inner><div class=dropdown><a href=/posts/ class="menu-item menu-more dropbtn" title=点击查看所有文章><i class="fas fa-fw fa-archive"></i>归档</a><div class="menu-more-content dropdown-content"><a href=/categories/><i class="fas fa-fw fa-th"></i>分类 </a><a href=/tags/><i class="fas fa-fw fa-tag"></i>标签 </a><a href=/hot/ title=文章热度Top15><i class="fas fa-fw fa-fire"></i>热度 </a><a href=/donation/ title=感谢打赏，老板大气~><i class="fas fa-fw fa-donate"></i>打赏 </a><a href=/about/><i class="fas fa-fw fa-at"></i>关于</a></div></div><a class=menu-item href=/friends/ title=欢迎申请友链><i class="fas fa-fw fa-link"></i>友链</a><div class=dropdown><a href=javascript:void(0); class="menu-item menu-more dropbtn" title=一些有意思的东东~><i class="fas fa-fw fa-fan fa-spin"></i>趣味</a><div class="menu-more-content dropdown-content"><a href=/funny/high/ title="前方高能♂ 小心外放！" target=_blank rel=noopener><i class="fas fa-fw fa-dizzy"></i>燥起来！ </a><a href=/funny/mikutap/ title=初音未来音乐游戏 target=_blank rel=noopener><i class="fas fa-fw fa-music"></i>在线打碟 </a><a href=/funny/catch-the-cat/ title=逮住那只猫!><i class="fas fa-fw fa-cat"></i>抓住猫咪</a></div></div><div class=dropdown><a href=/ class="menu-item menu-more dropbtn" title=回到首页><i class="fas fa-fw fa-atom"></i>站点</a><div class="menu-more-content dropdown-content"><a href=/bbs/ title=来留言吧~><i class="fas fa-fw fa-comment"></i>公告留言 </a><a href=https://seo.chinaz.com target=_blank rel=noopener><i class="fas fa-fw fa-chart-line"></i>SEO查询 </a><a href=https://www.ping.cn/http/lewky.cn target=_blank rel=noopener><i class="fas fa-fw fa-bezier-curve"></i>网站测速 </a><a href=/posts/e62c38c4.html/><i class="fas fa-fw fa-cog fa-spin"></i>建站日志</a></div></div><div class=dropdown><a href=javascript:void(0); class="menu-item menu-more dropbtn"><i class="fas fa-fw fa-book"></i>文档</a><div class="menu-more-content dropdown-content"><a href=https://gohugo.io/documentation/ target=_blank rel=noopener><i class="fas fa-fw fa-star"></i>Hugo文档 </a><a href=https://javanote.doc.lewky.cn/ title=尚在完善中~ target=_blank rel=noopener><i class="fab fa-fw fa-java"></i>Java 笔记</a></div></div><a class=menu-item href=/search/ title=渲染搜索结果需要等待几秒钟~><i class="fas fa-fw fa-search"></i>搜索
</a><span class="menu-item delimiter"></span><a href=https://travellings.link target=_blank class=menu-item rel=noopener title=开往-友链接力><i class="fas fa-fw fa-subway"></i></a><a href=https://rssblog.vercel.app/ class=menu-item target=_blank rel=noopener title=RSSBlog><i class="fas fa-fw fa-inbox"></i></a><a href=https://github.com/lewky class=menu-item target=_blank rel=noopener title=GitHub><i class="fab fa-fw fa-github"></i></a></div></div></div></header><header class=mobile id=header-mobile><div class=header-container><div class=header-wrapper><div class=header-title><a href=/ title="Yulin Lewis' Blog"><span class=header-title-pre><i class="fas fa-fw fa-atom"></i></span>雨临Lewis</a></div><div class=menu-toggle id=menu-toggle-mobile><span></span><span></span><span></span></div></div><div class=menu id=menu-mobile><div class=dropdown><a href=/posts/ class="menu-item menu-more dropbtn" title=点击查看所有文章><i class="fas fa-fw fa-archive"></i>归档</a><div class="menu-more-content dropdown-content"><a href=/categories/><i class="fas fa-fw fa-th"></i>分类 </a><a href=/tags/><i class="fas fa-fw fa-tag"></i>标签 </a><a href=/hot/ title=文章热度Top15><i class="fas fa-fw fa-fire"></i>热度 </a><a href=/donation/ title=感谢打赏，老板大气~><i class="fas fa-fw fa-donate"></i>打赏 </a><a href=/about/><i class="fas fa-fw fa-at"></i>关于</a></div></div><a class=menu-item href=/friends/ title=欢迎申请友链><i class="fas fa-fw fa-link"></i>友链</a><div class=dropdown><a href=javascript:void(0); class="menu-item menu-more dropbtn" title=一些有意思的东东~><i class="fas fa-fw fa-fan fa-spin"></i>趣味</a><div class="menu-more-content dropdown-content"><a href=/funny/high/ title="前方高能♂ 小心外放！" target=_blank rel=noopener><i class="fas fa-fw fa-dizzy"></i>燥起来！ </a><a href=/funny/mikutap/ title=初音未来音乐游戏 target=_blank rel=noopener><i class="fas fa-fw fa-music"></i>在线打碟 </a><a href=/funny/catch-the-cat/ title=逮住那只猫!><i class="fas fa-fw fa-cat"></i>抓住猫咪</a></div></div><div class=dropdown><a href=/ class="menu-item menu-more dropbtn" title=回到首页><i class="fas fa-fw fa-atom"></i>站点</a><div class="menu-more-content dropdown-content"><a href=/bbs/ title=来留言吧~><i class="fas fa-fw fa-comment"></i>公告留言 </a><a href=https://seo.chinaz.com target=_blank rel=noopener><i class="fas fa-fw fa-chart-line"></i>SEO查询 </a><a href=https://www.ping.cn/http/lewky.cn target=_blank rel=noopener><i class="fas fa-fw fa-bezier-curve"></i>网站测速 </a><a href=/posts/e62c38c4.html/><i class="fas fa-fw fa-cog fa-spin"></i>建站日志</a></div></div><div class=dropdown><a href=javascript:void(0); class="menu-item menu-more dropbtn"><i class="fas fa-fw fa-book"></i>文档</a><div class="menu-more-content dropdown-content"><a href=https://gohugo.io/documentation/ target=_blank rel=noopener><i class="fas fa-fw fa-star"></i>Hugo文档 </a><a href=https://javanote.doc.lewky.cn/ title=尚在完善中~ target=_blank rel=noopener><i class="fab fa-fw fa-java"></i>Java 笔记</a></div></div><a class=menu-item href=/search/ title=渲染搜索结果需要等待几秒钟~><i class="fas fa-fw fa-search"></i>搜索</a>
<a href=https://travellings.link target=_blank class=menu-item rel=noopener title=开往-友链接力><i class="fas fa-fw fa-subway"></i></a><a href=https://rssblog.vercel.app/ class=menu-item target=_blank rel=noopener title=RSSBlog><i class="fas fa-fw fa-inbox"></i></a><a href=https://github.com/lewky class=menu-item target=_blank rel=noopener title=GitHub><i class="fab fa-fw fa-github"></i></a></div></div></header><div class="search-dropdown desktop"><div id=search-dropdown-desktop></div></div><div class="search-dropdown mobile"><div id=search-dropdown-mobile></div></div><main class=main><div class=container><article class="page single"><h1 class="single-title animated flipInX">Java高并发秒杀API(三)之Web层</h1><div class=post-meta><div class=post-meta-line><span class=post-author><a href=/ title=Author rel=author class=author><i class="fas fa-user-circle fa-fw"></i>雨临Lewis</a></span>&nbsp;<span class=post-category>收录于 <a href=/categories/seckill/><i class="far fa-folder fa-fw"></i>seckill</a></span></div><div class=post-meta-line><i class="far fa-calendar fa-fw"></i>&nbsp;<time datetime=2017-10-05>2017-10-05</time>&nbsp;<i class="far fa-calendar-plus fa-fw"></i>&nbsp;<time datetime=2017-10-05>2017-10-05</time>&nbsp;<i class="fas fa-pencil-alt fa-fw"></i>&nbsp;约 5548 字
<i class="far fa-clock fa-fw"></i>&nbsp;预计阅读 12 分钟&nbsp;<span id=/posts/33818.html/ class=leancloud_visitors data-flag-title=Java高并发秒杀API(三)之Web层>
<i class="far fa-eye fa-fw"></i>&nbsp;<span class=leancloud-visitors-count></span>&nbsp;次阅读
</span>&nbsp;
<a href=#comments id=post-meta-vcount title=查看评论><i class="fas fa-comment fa-fw"></i>&nbsp;<span id=/posts/33818.html/ class=waline-comment-count></span>&nbsp;条评论</a></div></div><div class=content id=content><h2 id=1-设计前的分析><strong>1. 设计前的分析</strong></h2><blockquote><p><strong>Web层内容相关</strong></p></blockquote><ul><li>前端交互设计</li><li>Restful规范</li><li>SpringMVC</li></ul><ul><li>Bootstrap + jQuery</li></ul><blockquote><p><strong>前端页面流程</strong></p></blockquote><p><figure><a class=lightgallery href=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e5%89%8d%e7%ab%af%e9%a1%b5%e9%9d%a2%e6%b5%81%e7%a8%8b.jpg title=前端页面流程 data-thumbnail=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/前端页面流程.jpg data-sub-html="<h2> </h2><p>前端页面流程</p>"><img class=lazyload src=/svg/loading.min.svg data-src=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e5%89%8d%e7%ab%af%e9%a1%b5%e9%9d%a2%e6%b5%81%e7%a8%8b.jpg data-srcset="https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e5%89%8d%e7%ab%af%e9%a1%b5%e9%9d%a2%e6%b5%81%e7%a8%8b.jpg, https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e5%89%8d%e7%ab%af%e9%a1%b5%e9%9d%a2%e6%b5%81%e7%a8%8b.jpg 1.5x, https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e5%89%8d%e7%ab%af%e9%a1%b5%e9%9d%a2%e6%b5%81%e7%a8%8b.jpg 2x" data-sizes=auto alt=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/前端页面流程.jpg></a><figcaption class=image-caption>前端页面流程</figcaption></figure></p><blockquote><p><strong>详情页流程逻辑</strong></p></blockquote><p><figure><a class=lightgallery href=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e8%af%a6%e6%83%85%e9%a1%b5%e6%b5%81%e7%a8%8b%e9%80%bb%e8%be%91.jpg title=详情页流程逻辑 data-thumbnail=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/详情页流程逻辑.jpg data-sub-html="<h2> </h2><p>详情页流程逻辑</p>"><img class=lazyload src=/svg/loading.min.svg data-src=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e8%af%a6%e6%83%85%e9%a1%b5%e6%b5%81%e7%a8%8b%e9%80%bb%e8%be%91.jpg data-srcset="https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e8%af%a6%e6%83%85%e9%a1%b5%e6%b5%81%e7%a8%8b%e9%80%bb%e8%be%91.jpg, https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e8%af%a6%e6%83%85%e9%a1%b5%e6%b5%81%e7%a8%8b%e9%80%bb%e8%be%91.jpg 1.5x, https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e8%af%a6%e6%83%85%e9%a1%b5%e6%b5%81%e7%a8%8b%e9%80%bb%e8%be%91.jpg 2x" data-sizes=auto alt=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/详情页流程逻辑.jpg></a><figcaption class=image-caption>详情页流程逻辑</figcaption></figure></p><blockquote><p><strong>为什么要获取标准系统时间（服务器的时间）</strong></p></blockquote><p>用户可能处在不同时区，用户的电脑的系统时间可能不同。</p><blockquote><p><strong>Restful规范</strong></p></blockquote><p>Restful规范是一种优雅的URI表达方式：/模块/资源/{标识}/集合1/···</p><p>GET -> 查询操作</p><p>POST -> 添加/修改操作（用于非幂等操作）</p><p>PUT -> 修改操作（用于幂等操作）</p><p>DELETE -> 删除操作</p><blockquote><p><strong>怎么实现Restful接口</strong></p></blockquote><ul><li>@RequestMapping(value = &ldquo;/path&rdquo;,<font color=red>method = RequestMethod.GET</font>)</li><li>@RequestMapping(value = &ldquo;/path&rdquo;,<font color=red>method = RequestMethod.POST</font>)</li><li>@RequestMapping(value = &ldquo;/path&rdquo;,<font color=red>method = RequestMethod.PUT</font>)</li><li>@RequestMapping(value = &ldquo;/path&rdquo;,<font color=red>method = RequestMethod.DELETE</font>)</li></ul><blockquote><p><strong>非幂等操作和幂等操作</strong></p></blockquote><p>幂等性（idempotency）意味着对同一URL的多个请求应该返回同样的结果。在Restful规范中，GET、PUT、DELETE是幂等操作，只有POST是非幂等操作。</p><p>POST和PUT都可以用来创建和更新资源，二者的区别就是前者用于非幂等操作，后者用于幂等操作。</p><p>简单来说，使用POST方法请求创建一个资源，如果将这条请求重复发送N次，就会创建出N个资源；而如果用GET方法请求创建一个资源，就算重复发送该请求N次，也只会创建一个资源（就算第一次请求创建出来的资源）。</p><p>附：<a href=http://www.cnblogs.com/RunForLove/p/5640949.html target=_blank rel="noopener noreffer">《幂等和高并发在电商系统中的使用》</a></p><blockquote><p><strong>秒杀API的URL设计</strong></p></blockquote><p><figure><a class=lightgallery href=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e7%a7%92%e6%9d%80API%e7%9a%84URL%e8%ae%be%e8%ae%a1.jpg title=秒杀API的URL设计 data-thumbnail=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/秒杀API的URL设计.jpg data-sub-html="<h2> </h2><p>秒杀API的URL设计</p>"><img class=lazyload src=/svg/loading.min.svg data-src=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e7%a7%92%e6%9d%80API%e7%9a%84URL%e8%ae%be%e8%ae%a1.jpg data-srcset="https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e7%a7%92%e6%9d%80API%e7%9a%84URL%e8%ae%be%e8%ae%a1.jpg, https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e7%a7%92%e6%9d%80API%e7%9a%84URL%e8%ae%be%e8%ae%a1.jpg 1.5x, https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e7%a7%92%e6%9d%80API%e7%9a%84URL%e8%ae%be%e8%ae%a1.jpg 2x" data-sizes=auto alt=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/秒杀API的URL设计.jpg></a><figcaption class=image-caption>秒杀API的URL设计</figcaption></figure></p><blockquote><p><strong>@RequestMapping的映射技巧</strong></p></blockquote><p><figure><a class=lightgallery href=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e6%b3%a8%e8%a7%a3%e6%98%a0%e5%b0%84%e6%8a%80%e5%b7%a7.jpg title=注解映射技巧 data-thumbnail=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/注解映射技巧.jpg data-sub-html="<h2> </h2><p>注解映射技巧</p>"><img class=lazyload src=/svg/loading.min.svg data-src=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e6%b3%a8%e8%a7%a3%e6%98%a0%e5%b0%84%e6%8a%80%e5%b7%a7.jpg data-srcset="https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e6%b3%a8%e8%a7%a3%e6%98%a0%e5%b0%84%e6%8a%80%e5%b7%a7.jpg, https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e6%b3%a8%e8%a7%a3%e6%98%a0%e5%b0%84%e6%8a%80%e5%b7%a7.jpg 1.5x, https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/%e6%b3%a8%e8%a7%a3%e6%98%a0%e5%b0%84%e6%8a%80%e5%b7%a7.jpg 2x" data-sizes=auto alt=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/posts/project/seckill/注解映射技巧.jpg></a><figcaption class=image-caption>注解映射技巧</figcaption></figure></p><blockquote><p><strong>请求方法细节处理</strong></p></blockquote><ol><li>请求参数绑定</li><li>请求方法限制</li><li>请求转发和重定向</li><li>数据模型赋值</li><li>返回json数据</li><li>Cookie访问</li></ol><h2 id=2-整合配置springmvc框架><strong>2. 整合配置SpringMVC框架</strong></h2><h3 id=21-配置webxml><strong>2.1 配置web.xml</strong></h3><div class=highlight><div class=chroma><table class=lntable><tr><td class=lntd><pre class=chroma><code><span class=lnt> 1
</span><span class=lnt> 2
</span><span class=lnt> 3
</span><span class=lnt> 4
</span><span class=lnt> 5
</span><span class=lnt> 6
</span><span class=lnt> 7
</span><span class=lnt> 8
</span><span class=lnt> 9
</span><span class=lnt>10
</span><span class=lnt>11
</span><span class=lnt>12
</span><span class=lnt>13
</span><span class=lnt>14
</span><span class=lnt>15
</span><span class=lnt>16
</span><span class=lnt>17
</span><span class=lnt>18
</span><span class=lnt>19
</span><span class=lnt>20
</span><span class=lnt>21
</span><span class=lnt>22
</span><span class=lnt>23
</span><span class=lnt>24
</span></code></pre></td><td class=lntd><pre class=chroma><code class=language-xml data-lang=xml>	<span class=nt>&lt;web-app</span> <span class=na>xmlns=</span><span class=s>&#34;http://java.sun.com/xml/ns/javaee&#34;</span>
	         <span class=na>xmlns:xsi=</span><span class=s>&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span>
	         <span class=na>xsi:schemaLocation=</span><span class=s>&#34;http://java.sun.com/xml/ns/javaee
</span><span class=s>	                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&#34;</span>
	         <span class=na>version=</span><span class=s>&#34;3.0&#34;</span>
	         <span class=na>metadata-complete=</span><span class=s>&#34;true&#34;</span><span class=nt>&gt;</span>
		<span class=c>&lt;!--用maven创建的web-app需要修改servlet的版本为3.0 --&gt;</span>
		<span class=c>&lt;!--配置DispatcherServlet --&gt;</span>
		<span class=nt>&lt;servlet&gt;</span>
			<span class=nt>&lt;servlet-name&gt;</span>seckill-dispatcher<span class=nt>&lt;/servlet-name&gt;</span>
			<span class=nt>&lt;servlet-class&gt;</span>org.springframework.web.servlet.DispatcherServlet<span class=nt>&lt;/servlet-class&gt;</span>
			<span class=c>&lt;!-- 配置SpringMVC 需要配置的文件 spring-dao.xml，spring-service.xml,spring-web.xml 
</span><span class=c>				MyBatis -&gt; Spring -&gt; SpringMVC --&gt;</span>
			<span class=nt>&lt;init-param&gt;</span>
				<span class=nt>&lt;param-name&gt;</span>contextConfigLocation<span class=nt>&lt;/param-name&gt;</span>
				<span class=nt>&lt;param-value&gt;</span>classpath:spring/spring-*.xml<span class=nt>&lt;/param-value&gt;</span>
			<span class=nt>&lt;/init-param&gt;</span>
		<span class=nt>&lt;/servlet&gt;</span>
		<span class=nt>&lt;servlet-mapping&gt;</span>
			<span class=nt>&lt;servlet-name&gt;</span>seckill-dispatcher<span class=nt>&lt;/servlet-name&gt;</span>
			<span class=c>&lt;!--默认匹配所有请求 --&gt;</span>
			<span class=nt>&lt;url-pattern&gt;</span>/<span class=nt>&lt;/url-pattern&gt;</span>
		<span class=nt>&lt;/servlet-mapping&gt;</span>
	<span class=nt>&lt;/web-app&gt;</span>
</code></pre></td></tr></table></div></div><blockquote><p><strong>注意</strong></p></blockquote><ul><li>这里的Servlet版本是3.0，对应Tomcat7.0版本</li><li>由于我们的配置文件都是以<code>spring-</code>开头命名的，所以可以用通配符*一次性全部加载</li><li><code>url-pattern</code>设置为<code>/</code>，这是使用了Restful的规范；在使用Struts框架时我们配置的是*.do之类的，这是一种比较丑陋的表达方式</li></ul><h3 id=22-在srcmainresourcesspring包下建立spring-webxml><strong>2.2 在<code>src/main/resources/spring</code>包下建立spring-web.xml</strong></h3><div class=highlight><div class=chroma><table class=lntable><tr><td class=lntd><pre class=chroma><code><span class=lnt> 1
</span><span class=lnt> 2
</span><span class=lnt> 3
</span><span class=lnt> 4
</span><span class=lnt> 5
</span><span class=lnt> 6
</span><span class=lnt> 7
</span><span class=lnt> 8
</span><span class=lnt> 9
</span><span class=lnt>10
</span><span class=lnt>11
</span><span class=lnt>12
</span><span class=lnt>13
</span><span class=lnt>14
</span><span class=lnt>15
</span><span class=lnt>16
</span><span class=lnt>17
</span><span class=lnt>18
</span><span class=lnt>19
</span><span class=lnt>20
</span><span class=lnt>21
</span><span class=lnt>22
</span><span class=lnt>23
</span><span class=lnt>24
</span><span class=lnt>25
</span><span class=lnt>26
</span><span class=lnt>27
</span><span class=lnt>28
</span><span class=lnt>29
</span><span class=lnt>30
</span><span class=lnt>31
</span><span class=lnt>32
</span><span class=lnt>33
</span><span class=lnt>34
</span><span class=lnt>35
</span><span class=lnt>36
</span></code></pre></td><td class=lntd><pre class=chroma><code class=language-xml data-lang=xml>	<span class=cp>&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
	<span class=nt>&lt;beans</span> <span class=na>xmlns=</span><span class=s>&#34;http://www.springframework.org/schema/beans&#34;</span>
	       <span class=na>xmlns:xsi=</span><span class=s>&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span>
	       <span class=na>xmlns:context=</span><span class=s>&#34;http://www.springframework.org/schema/context&#34;</span>
	       <span class=na>xmlns:mvc=</span><span class=s>&#34;http://www.springframework.org/schema/mvc&#34;</span>
	       <span class=na>xsi:schemaLocation=</span><span class=s>&#34;http://www.springframework.org/schema/beans
</span><span class=s>	        http://www.springframework.org/schema/beans/spring-beans.xsd
</span><span class=s>	        http://www.springframework.org/schema/context
</span><span class=s>	        http://www.springframework.org/schema/context/spring-context.xsd
</span><span class=s>	        http://www.springframework.org/schema/mvc
</span><span class=s>	        http://www.springframework.org/schema/mvc/spring-mvc.xsd&#34;</span><span class=nt>&gt;</span>
	
	    <span class=c>&lt;!--配置spring mvc--&gt;</span>
	    <span class=c>&lt;!--1,开启springmvc注解模式
</span><span class=c>	    a.自动注册DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter
</span><span class=c>	    b.默认提供一系列的功能:数据绑定，数字和日期的format@NumberFormat,@DateTimeFormat
</span><span class=c>	    c:xml,json的默认读写支持--&gt;</span>
	    <span class=nt>&lt;mvc:annotation-driven/&gt;</span>
	
	    <span class=c>&lt;!--2.静态资源默认servlet配置--&gt;</span>
	    <span class=c>&lt;!--
</span><span class=c>	        1).加入对静态资源处理：js,gif,png
</span><span class=c>	        2).允许使用 &#34;/&#34; 做整体映射
</span><span class=c>	    --&gt;</span>
	    <span class=nt>&lt;mvc:default-servlet-handler/&gt;</span>
	
	    <span class=c>&lt;!--3：配置JSP 显示ViewResolver--&gt;</span>
	    <span class=nt>&lt;bean</span> <span class=na>class=</span><span class=s>&#34;org.springframework.web.servlet.view.InternalResourceViewResolver&#34;</span><span class=nt>&gt;</span>
	        <span class=nt>&lt;property</span> <span class=na>name=</span><span class=s>&#34;viewClass&#34;</span> <span class=na>value=</span><span class=s>&#34;org.springframework.web.servlet.view.JstlView&#34;</span><span class=nt>/&gt;</span>
	        <span class=nt>&lt;property</span> <span class=na>name=</span><span class=s>&#34;prefix&#34;</span> <span class=na>value=</span><span class=s>&#34;/WEB-INF/jsp/&#34;</span><span class=nt>/&gt;</span>
	        <span class=nt>&lt;property</span> <span class=na>name=</span><span class=s>&#34;suffix&#34;</span> <span class=na>value=</span><span class=s>&#34;.jsp&#34;</span><span class=nt>/&gt;</span>
	    <span class=nt>&lt;/bean&gt;</span>
	
	    <span class=c>&lt;!--4:扫描web相关的controller--&gt;</span>
	    <span class=nt>&lt;context:component-scan</span> <span class=na>base-package=</span><span class=s>&#34;com.lewis.web&#34;</span><span class=nt>/&gt;</span>
	<span class=nt>&lt;/beans&gt;</span>
</code></pre></td></tr></table></div></div><h2 id=3-controller设计><strong>3. Controller设计</strong></h2><p>Controller中的每一个方法都对应我们系统中的一个资源URL，其设计应该遵循Restful接口的设计风格。</p><h3 id=31-在java包下新建comlewisweb包在该包下新建seckillcontrollerjava><strong>3.1 在java包下新建<code>com.lewis.web</code>包，在该包下新建SeckillController.java</strong></h3><div class=highlight><div class=chroma><table class=lntable><tr><td class=lntd><pre class=chroma><code><span class=lnt> 1
</span><span class=lnt> 2
</span><span class=lnt> 3
</span><span class=lnt> 4
</span><span class=lnt> 5
</span><span class=lnt> 6
</span><span class=lnt> 7
</span><span class=lnt> 8
</span><span class=lnt> 9
</span><span class=lnt>10
</span><span class=lnt>11
</span><span class=lnt>12
</span><span class=lnt>13
</span><span class=lnt>14
</span><span class=lnt>15
</span><span class=lnt>16
</span><span class=lnt>17
</span><span class=lnt>18
</span><span class=lnt>19
</span><span class=lnt>20
</span><span class=lnt>21
</span><span class=lnt>22
</span><span class=lnt>23
</span><span class=lnt>24
</span><span class=lnt>25
</span><span class=lnt>26
</span><span class=lnt>27
</span><span class=lnt>28
</span><span class=lnt>29
</span><span class=lnt>30
</span><span class=lnt>31
</span><span class=lnt>32
</span><span class=lnt>33
</span><span class=lnt>34
</span><span class=lnt>35
</span><span class=lnt>36
</span><span class=lnt>37
</span><span class=lnt>38
</span><span class=lnt>39
</span><span class=lnt>40
</span><span class=lnt>41
</span><span class=lnt>42
</span><span class=lnt>43
</span><span class=lnt>44
</span><span class=lnt>45
</span><span class=lnt>46
</span><span class=lnt>47
</span><span class=lnt>48
</span><span class=lnt>49
</span><span class=lnt>50
</span><span class=lnt>51
</span><span class=lnt>52
</span><span class=lnt>53
</span><span class=lnt>54
</span><span class=lnt>55
</span><span class=lnt>56
</span><span class=lnt>57
</span><span class=lnt>58
</span><span class=lnt>59
</span><span class=lnt>60
</span><span class=lnt>61
</span><span class=lnt>62
</span><span class=lnt>63
</span><span class=lnt>64
</span><span class=lnt>65
</span><span class=lnt>66
</span><span class=lnt>67
</span><span class=lnt>68
</span><span class=lnt>69
</span><span class=lnt>70
</span><span class=lnt>71
</span><span class=lnt>72
</span><span class=lnt>73
</span><span class=lnt>74
</span><span class=lnt>75
</span><span class=lnt>76
</span><span class=lnt>77
</span><span class=lnt>78
</span><span class=lnt>79
</span><span class=lnt>80
</span><span class=lnt>81
</span><span class=lnt>82
</span><span class=lnt>83
</span><span class=lnt>84
</span><span class=lnt>85
</span><span class=lnt>86
</span><span class=lnt>87
</span><span class=lnt>88
</span><span class=lnt>89
</span><span class=lnt>90
</span><span class=lnt>91
</span><span class=lnt>92
</span><span class=lnt>93
</span><span class=lnt>94
</span><span class=lnt>95
</span><span class=lnt>96
</span><span class=lnt>97
</span></code></pre></td><td class=lntd><pre class=chroma><code class=language-java data-lang=java>	<span class=nd>@Controller</span>
	<span class=nd>@RequestMapping</span><span class=o>(</span><span class=s>&#34;/seckill&#34;</span><span class=o>)</span><span class=c1>//url:模块/资源/{}/细分
</span><span class=c1></span>	<span class=kd>public</span> <span class=kd>class</span> <span class=nc>SeckillController</span>
	<span class=o>{</span>
	    <span class=nd>@Autowired</span>
	    <span class=kd>private</span> <span class=n>SeckillService</span> <span class=n>seckillService</span><span class=o>;</span>
	
	    <span class=nd>@RequestMapping</span><span class=o>(</span><span class=n>value</span> <span class=o>=</span> <span class=s>&#34;/list&#34;</span><span class=o>,</span><span class=n>method</span> <span class=o>=</span> <span class=n>RequestMethod</span><span class=o>.</span><span class=na>GET</span><span class=o>)</span>
	    <span class=kd>public</span> <span class=n>String</span> <span class=nf>list</span><span class=o>(</span><span class=n>Model</span> <span class=n>model</span><span class=o>)</span>
	    <span class=o>{</span>
	        <span class=c1>//list.jsp+mode=ModelAndView
</span><span class=c1></span>	        <span class=c1>//获取列表页
</span><span class=c1></span>	        <span class=n>List</span><span class=o>&lt;</span><span class=n>Seckill</span><span class=o>&gt;</span> <span class=n>list</span><span class=o>=</span><span class=n>seckillService</span><span class=o>.</span><span class=na>getSeckillList</span><span class=o>();</span>
	        <span class=n>model</span><span class=o>.</span><span class=na>addAttribute</span><span class=o>(</span><span class=s>&#34;list&#34;</span><span class=o>,</span><span class=n>list</span><span class=o>);</span>
	        <span class=k>return</span> <span class=s>&#34;list&#34;</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=nd>@RequestMapping</span><span class=o>(</span><span class=n>value</span> <span class=o>=</span> <span class=s>&#34;/{seckillId}/detail&#34;</span><span class=o>,</span><span class=n>method</span> <span class=o>=</span> <span class=n>RequestMethod</span><span class=o>.</span><span class=na>GET</span><span class=o>)</span>
	    <span class=kd>public</span> <span class=n>String</span> <span class=nf>detail</span><span class=o>(</span><span class=nd>@PathVariable</span><span class=o>(</span><span class=s>&#34;seckillId&#34;</span><span class=o>)</span> <span class=n>Long</span> <span class=n>seckillId</span><span class=o>,</span> <span class=n>Model</span> <span class=n>model</span><span class=o>)</span>
	    <span class=o>{</span>
	        <span class=k>if</span> <span class=o>(</span><span class=n>seckillId</span> <span class=o>==</span> <span class=kc>null</span><span class=o>)</span>
	        <span class=o>{</span>
	            <span class=k>return</span> <span class=s>&#34;redirect:/seckill/list&#34;</span><span class=o>;</span>
	        <span class=o>}</span>
	
	        <span class=n>Seckill</span> <span class=n>seckill</span><span class=o>=</span><span class=n>seckillService</span><span class=o>.</span><span class=na>getById</span><span class=o>(</span><span class=n>seckillId</span><span class=o>);</span>
	        <span class=k>if</span> <span class=o>(</span><span class=n>seckill</span><span class=o>==</span><span class=kc>null</span><span class=o>)</span>
	        <span class=o>{</span>
	            <span class=k>return</span> <span class=s>&#34;forward:/seckill/list&#34;</span><span class=o>;</span>
	        <span class=o>}</span>
	
	        <span class=n>model</span><span class=o>.</span><span class=na>addAttribute</span><span class=o>(</span><span class=s>&#34;seckill&#34;</span><span class=o>,</span><span class=n>seckill</span><span class=o>);</span>
	
	        <span class=k>return</span> <span class=s>&#34;detail&#34;</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=c1>//ajax ,json暴露秒杀接口的方法
</span><span class=c1></span>	    <span class=nd>@RequestMapping</span><span class=o>(</span><span class=n>value</span> <span class=o>=</span> <span class=s>&#34;/{seckillId}/exposer&#34;</span><span class=o>,</span>
	                    <span class=n>method</span> <span class=o>=</span> <span class=n>RequestMethod</span><span class=o>.</span><span class=na>GET</span><span class=o>,</span>
	                    <span class=n>produces</span> <span class=o>=</span> <span class=o>{</span><span class=s>&#34;application/json;charset=UTF-8&#34;</span><span class=o>})</span>
	    <span class=nd>@ResponseBody</span>
	    <span class=kd>public</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>Exposer</span><span class=o>&gt;</span> <span class=nf>exposer</span><span class=o>(</span><span class=nd>@PathVariable</span><span class=o>(</span><span class=s>&#34;seckillId&#34;</span><span class=o>)</span> <span class=n>Long</span> <span class=n>seckillId</span><span class=o>)</span>
	    <span class=o>{</span>
	        <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>Exposer</span><span class=o>&gt;</span> <span class=n>result</span><span class=o>;</span>
	        <span class=k>try</span><span class=o>{</span>
	            <span class=n>Exposer</span> <span class=n>exposer</span><span class=o>=</span><span class=n>seckillService</span><span class=o>.</span><span class=na>exportSeckillUrl</span><span class=o>(</span><span class=n>seckillId</span><span class=o>);</span>
	            <span class=n>result</span><span class=o>=</span><span class=k>new</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>Exposer</span><span class=o>&gt;(</span><span class=kc>true</span><span class=o>,</span><span class=n>exposer</span><span class=o>);</span>
	        <span class=o>}</span><span class=k>catch</span> <span class=o>(</span><span class=n>Exception</span> <span class=n>e</span><span class=o>)</span>
	        <span class=o>{</span>
	            <span class=n>e</span><span class=o>.</span><span class=na>printStackTrace</span><span class=o>();</span>
	            <span class=n>result</span><span class=o>=</span><span class=k>new</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>Exposer</span><span class=o>&gt;(</span><span class=kc>false</span><span class=o>,</span><span class=n>e</span><span class=o>.</span><span class=na>getMessage</span><span class=o>());</span>
	        <span class=o>}</span>
	
	        <span class=k>return</span> <span class=n>result</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=nd>@RequestMapping</span><span class=o>(</span><span class=n>value</span> <span class=o>=</span> <span class=s>&#34;/{seckillId}/{md5}/execution&#34;</span><span class=o>,</span>
	            <span class=n>method</span> <span class=o>=</span> <span class=n>RequestMethod</span><span class=o>.</span><span class=na>POST</span><span class=o>,</span>
	            <span class=n>produces</span> <span class=o>=</span> <span class=o>{</span><span class=s>&#34;application/json;charset=UTF-8&#34;</span><span class=o>})</span>
	    <span class=nd>@ResponseBody</span>
	    <span class=kd>public</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>SeckillExecution</span><span class=o>&gt;</span> <span class=nf>execute</span><span class=o>(</span><span class=nd>@PathVariable</span><span class=o>(</span><span class=s>&#34;seckillId&#34;</span><span class=o>)</span> <span class=n>Long</span> <span class=n>seckillId</span><span class=o>,</span>
	                                                   <span class=nd>@PathVariable</span><span class=o>(</span><span class=s>&#34;md5&#34;</span><span class=o>)</span> <span class=n>String</span> <span class=n>md5</span><span class=o>,</span>
	                                                   <span class=nd>@CookieValue</span><span class=o>(</span><span class=n>value</span> <span class=o>=</span> <span class=s>&#34;userPhone&#34;</span><span class=o>,</span><span class=n>required</span> <span class=o>=</span> <span class=kc>false</span><span class=o>)</span> <span class=n>Long</span> <span class=n>userPhone</span><span class=o>)</span>
	    <span class=o>{</span>
	        <span class=k>if</span> <span class=o>(</span><span class=n>userPhone</span><span class=o>==</span><span class=kc>null</span><span class=o>)</span>
	        <span class=o>{</span>
	            <span class=k>return</span> <span class=k>new</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>SeckillExecution</span><span class=o>&gt;(</span><span class=kc>false</span><span class=o>,</span><span class=s>&#34;未注册&#34;</span><span class=o>);</span>
	        <span class=o>}</span>
	
	        <span class=k>try</span> <span class=o>{</span>
	            <span class=n>SeckillExecution</span> <span class=n>execution</span> <span class=o>=</span> <span class=n>seckillService</span><span class=o>.</span><span class=na>executeSeckill</span><span class=o>(</span><span class=n>seckillId</span><span class=o>,</span> <span class=n>userPhone</span><span class=o>,</span> <span class=n>md5</span><span class=o>);</span>
	            <span class=k>return</span> <span class=k>new</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>SeckillExecution</span><span class=o>&gt;(</span><span class=kc>true</span><span class=o>,</span> <span class=n>execution</span><span class=o>);</span>
	        <span class=o>}</span><span class=k>catch</span> <span class=o>(</span><span class=n>RepeatKillException</span> <span class=n>e1</span><span class=o>)</span>
	        <span class=o>{</span>
	            <span class=n>SeckillExecution</span> <span class=n>execution</span><span class=o>=</span><span class=k>new</span> <span class=n>SeckillExecution</span><span class=o>(</span><span class=n>seckillId</span><span class=o>,</span> <span class=n>SeckillStatEnum</span><span class=o>.</span><span class=na>REPEAT_KILL</span><span class=o>);</span>
	            <span class=k>return</span> <span class=k>new</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>SeckillExecution</span><span class=o>&gt;(</span><span class=kc>true</span><span class=o>,</span><span class=n>execution</span><span class=o>);</span>
	        <span class=o>}</span><span class=k>catch</span> <span class=o>(</span><span class=n>SeckillCloseException</span> <span class=n>e2</span><span class=o>)</span>
	        <span class=o>{</span>
	            <span class=n>SeckillExecution</span> <span class=n>execution</span><span class=o>=</span><span class=k>new</span> <span class=n>SeckillExecution</span><span class=o>(</span><span class=n>seckillId</span><span class=o>,</span> <span class=n>SeckillStatEnum</span><span class=o>.</span><span class=na>END</span><span class=o>);</span>
	            <span class=k>return</span> <span class=k>new</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>SeckillExecution</span><span class=o>&gt;(</span><span class=kc>true</span><span class=o>,</span><span class=n>execution</span><span class=o>);</span>
	        <span class=o>}</span>
	        <span class=k>catch</span> <span class=o>(</span><span class=n>Exception</span> <span class=n>e</span><span class=o>)</span>
	        <span class=o>{</span>
	            <span class=n>SeckillExecution</span> <span class=n>execution</span><span class=o>=</span><span class=k>new</span> <span class=n>SeckillExecution</span><span class=o>(</span><span class=n>seckillId</span><span class=o>,</span> <span class=n>SeckillStatEnum</span><span class=o>.</span><span class=na>INNER_ERROR</span><span class=o>);</span>
	            <span class=k>return</span> <span class=k>new</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>SeckillExecution</span><span class=o>&gt;(</span><span class=kc>true</span><span class=o>,</span><span class=n>execution</span><span class=o>);</span>
	        <span class=o>}</span>
	    <span class=o>}</span>
	
	    <span class=c1>//获取系统时间
</span><span class=c1></span>	    <span class=nd>@RequestMapping</span><span class=o>(</span><span class=n>value</span> <span class=o>=</span> <span class=s>&#34;/time/now&#34;</span><span class=o>,</span><span class=n>method</span> <span class=o>=</span> <span class=n>RequestMethod</span><span class=o>.</span><span class=na>GET</span><span class=o>)</span>
	    <span class=nd>@ResponseBody</span>
	    <span class=kd>public</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>Long</span><span class=o>&gt;</span> <span class=nf>time</span><span class=o>()</span>
	    <span class=o>{</span>
	        <span class=n>Date</span> <span class=n>now</span><span class=o>=</span><span class=k>new</span> <span class=n>Date</span><span class=o>();</span>
	        <span class=k>return</span> <span class=k>new</span> <span class=n>SeckillResult</span><span class=o>&lt;</span><span class=n>Long</span><span class=o>&gt;(</span><span class=kc>true</span><span class=o>,</span><span class=n>now</span><span class=o>.</span><span class=na>getTime</span><span class=o>());</span>
	    <span class=o>}</span>
	<span class=o>}</span>
</code></pre></td></tr></table></div></div><blockquote><p><strong>注意</strong></p></blockquote><p>SpringMVC在处理Cookie时有个小问题：如果找不到对应的Cookie会报错，所以设置为<code>required=false</code>，将Cookie是否存在的逻辑判断放到代码中来判断。</p><blockquote><p><strong>关于异常的捕捉</strong></p></blockquote><p>Service层中的抛出异常是为了让Spring能够回滚，Controller层中捕获异常是为了将异常转换为对应的Json供前台使用，缺一不可。</p><h3 id=32-在dto包下新建一个seckillresult><strong>3.2 在dto包下新建一个SeckillResult</strong></h3><div class=highlight><div class=chroma><table class=lntable><tr><td class=lntd><pre class=chroma><code><span class=lnt> 1
</span><span class=lnt> 2
</span><span class=lnt> 3
</span><span class=lnt> 4
</span><span class=lnt> 5
</span><span class=lnt> 6
</span><span class=lnt> 7
</span><span class=lnt> 8
</span><span class=lnt> 9
</span><span class=lnt>10
</span><span class=lnt>11
</span><span class=lnt>12
</span><span class=lnt>13
</span><span class=lnt>14
</span><span class=lnt>15
</span><span class=lnt>16
</span><span class=lnt>17
</span><span class=lnt>18
</span><span class=lnt>19
</span><span class=lnt>20
</span><span class=lnt>21
</span><span class=lnt>22
</span><span class=lnt>23
</span><span class=lnt>24
</span><span class=lnt>25
</span><span class=lnt>26
</span><span class=lnt>27
</span><span class=lnt>28
</span><span class=lnt>29
</span><span class=lnt>30
</span><span class=lnt>31
</span><span class=lnt>32
</span><span class=lnt>33
</span><span class=lnt>34
</span><span class=lnt>35
</span><span class=lnt>36
</span><span class=lnt>37
</span><span class=lnt>38
</span><span class=lnt>39
</span><span class=lnt>40
</span><span class=lnt>41
</span><span class=lnt>42
</span></code></pre></td><td class=lntd><pre class=chroma><code class=language-java data-lang=java>	<span class=c1>//将所有的ajax请求返回类型，全部封装成json数据
</span><span class=c1></span>	<span class=kd>public</span> <span class=kd>class</span> <span class=nc>SeckillResult</span><span class=o>&lt;</span><span class=n>T</span><span class=o>&gt;</span> <span class=o>{</span>
	
	    <span class=c1>//请求是否成功
</span><span class=c1></span>	    <span class=kd>private</span> <span class=kt>boolean</span> <span class=n>success</span><span class=o>;</span>
	    <span class=kd>private</span> <span class=n>T</span> <span class=n>data</span><span class=o>;</span>
	    <span class=kd>private</span> <span class=n>String</span> <span class=n>error</span><span class=o>;</span>
	
	    <span class=kd>public</span> <span class=nf>SeckillResult</span><span class=o>(</span><span class=kt>boolean</span> <span class=n>success</span><span class=o>,</span> <span class=n>T</span> <span class=n>data</span><span class=o>)</span> <span class=o>{</span>
	        <span class=k>this</span><span class=o>.</span><span class=na>success</span> <span class=o>=</span> <span class=n>success</span><span class=o>;</span>
	        <span class=k>this</span><span class=o>.</span><span class=na>data</span> <span class=o>=</span> <span class=n>data</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=kd>public</span> <span class=nf>SeckillResult</span><span class=o>(</span><span class=kt>boolean</span> <span class=n>success</span><span class=o>,</span> <span class=n>String</span> <span class=n>error</span><span class=o>)</span> <span class=o>{</span>
	        <span class=k>this</span><span class=o>.</span><span class=na>success</span> <span class=o>=</span> <span class=n>success</span><span class=o>;</span>
	        <span class=k>this</span><span class=o>.</span><span class=na>error</span> <span class=o>=</span> <span class=n>error</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=kd>public</span> <span class=kt>boolean</span> <span class=nf>isSuccess</span><span class=o>()</span> <span class=o>{</span>
	        <span class=k>return</span> <span class=n>success</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=kd>public</span> <span class=kt>void</span> <span class=nf>setSuccess</span><span class=o>(</span><span class=kt>boolean</span> <span class=n>success</span><span class=o>)</span> <span class=o>{</span>
	        <span class=k>this</span><span class=o>.</span><span class=na>success</span> <span class=o>=</span> <span class=n>success</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=kd>public</span> <span class=n>T</span> <span class=nf>getData</span><span class=o>()</span> <span class=o>{</span>
	        <span class=k>return</span> <span class=n>data</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=kd>public</span> <span class=kt>void</span> <span class=nf>setData</span><span class=o>(</span><span class=n>T</span> <span class=n>data</span><span class=o>)</span> <span class=o>{</span>
	        <span class=k>this</span><span class=o>.</span><span class=na>data</span> <span class=o>=</span> <span class=n>data</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=kd>public</span> <span class=n>String</span> <span class=nf>getError</span><span class=o>()</span> <span class=o>{</span>
	        <span class=k>return</span> <span class=n>error</span><span class=o>;</span>
	    <span class=o>}</span>
	
	    <span class=kd>public</span> <span class=kt>void</span> <span class=nf>setError</span><span class=o>(</span><span class=n>String</span> <span class=n>error</span><span class=o>)</span> <span class=o>{</span>
	        <span class=k>this</span><span class=o>.</span><span class=na>error</span> <span class=o>=</span> <span class=n>error</span><span class=o>;</span>
	    <span class=o>}</span>
	<span class=o>}</span>
</code></pre></td></tr></table></div></div><blockquote><p><strong>注意</strong></p></blockquote><p>SeckillResult是一个VO类(View Object)，属于DTO层，用来封装json结果，方便页面取值；在这里，将其设计成泛型<t>，就可以和灵活地往里边封装各种类型的对象。</p><p>这里的success属性不是指秒杀执行的结果，而是指页面是否发送请求成功，至于秒杀之后是否成功的这个结果则是封装到了data属性里。</p><h2 id=4-基于bootstrap开发页面><strong>4. 基于Bootstrap开发页面</strong></h2><p>由于项目的前端页面都是由Bootstrap开发的,所以需要先去下载Bootstrap或者是使用在线的CDN服务。而Bootstrap又是依赖于jQuery的，所以需要先引入jQuery。</p><h3 id=41-在webapp下建立resources目录接着建立script目录建立seckilljs><strong>4.1 在<code>webapp</code>下建立<code>resources</code>目录，接着建立<code>script</code>目录，建立seckill.js</strong></h3><div class=highlight><div class=chroma><table class=lntable><tr><td class=lntd><pre class=chroma><code><span class=lnt>  1
</span><span class=lnt>  2
</span><span class=lnt>  3
</span><span class=lnt>  4
</span><span class=lnt>  5
</span><span class=lnt>  6
</span><span class=lnt>  7
</span><span class=lnt>  8
</span><span class=lnt>  9
</span><span class=lnt> 10
</span><span class=lnt> 11
</span><span class=lnt> 12
</span><span class=lnt> 13
</span><span class=lnt> 14
</span><span class=lnt> 15
</span><span class=lnt> 16
</span><span class=lnt> 17
</span><span class=lnt> 18
</span><span class=lnt> 19
</span><span class=lnt> 20
</span><span class=lnt> 21
</span><span class=lnt> 22
</span><span class=lnt> 23
</span><span class=lnt> 24
</span><span class=lnt> 25
</span><span class=lnt> 26
</span><span class=lnt> 27
</span><span class=lnt> 28
</span><span class=lnt> 29
</span><span class=lnt> 30
</span><span class=lnt> 31
</span><span class=lnt> 32
</span><span class=lnt> 33
</span><span class=lnt> 34
</span><span class=lnt> 35
</span><span class=lnt> 36
</span><span class=lnt> 37
</span><span class=lnt> 38
</span><span class=lnt> 39
</span><span class=lnt> 40
</span><span class=lnt> 41
</span><span class=lnt> 42
</span><span class=lnt> 43
</span><span class=lnt> 44
</span><span class=lnt> 45
</span><span class=lnt> 46
</span><span class=lnt> 47
</span><span class=lnt> 48
</span><span class=lnt> 49
</span><span class=lnt> 50
</span><span class=lnt> 51
</span><span class=lnt> 52
</span><span class=lnt> 53
</span><span class=lnt> 54
</span><span class=lnt> 55
</span><span class=lnt> 56
</span><span class=lnt> 57
</span><span class=lnt> 58
</span><span class=lnt> 59
</span><span class=lnt> 60
</span><span class=lnt> 61
</span><span class=lnt> 62
</span><span class=lnt> 63
</span><span class=lnt> 64
</span><span class=lnt> 65
</span><span class=lnt> 66
</span><span class=lnt> 67
</span><span class=lnt> 68
</span><span class=lnt> 69
</span><span class=lnt> 70
</span><span class=lnt> 71
</span><span class=lnt> 72
</span><span class=lnt> 73
</span><span class=lnt> 74
</span><span class=lnt> 75
</span><span class=lnt> 76
</span><span class=lnt> 77
</span><span class=lnt> 78
</span><span class=lnt> 79
</span><span class=lnt> 80
</span><span class=lnt> 81
</span><span class=lnt> 82
</span><span class=lnt> 83
</span><span class=lnt> 84
</span><span class=lnt> 85
</span><span class=lnt> 86
</span><span class=lnt> 87
</span><span class=lnt> 88
</span><span class=lnt> 89
</span><span class=lnt> 90
</span><span class=lnt> 91
</span><span class=lnt> 92
</span><span class=lnt> 93
</span><span class=lnt> 94
</span><span class=lnt> 95
</span><span class=lnt> 96
</span><span class=lnt> 97
</span><span class=lnt> 98
</span><span class=lnt> 99
</span><span class=lnt>100
</span><span class=lnt>101
</span><span class=lnt>102
</span><span class=lnt>103
</span><span class=lnt>104
</span><span class=lnt>105
</span><span class=lnt>106
</span><span class=lnt>107
</span><span class=lnt>108
</span><span class=lnt>109
</span><span class=lnt>110
</span><span class=lnt>111
</span><span class=lnt>112
</span><span class=lnt>113
</span><span class=lnt>114
</span><span class=lnt>115
</span><span class=lnt>116
</span><span class=lnt>117
</span><span class=lnt>118
</span><span class=lnt>119
</span><span class=lnt>120
</span><span class=lnt>121
</span><span class=lnt>122
</span><span class=lnt>123
</span><span class=lnt>124
</span><span class=lnt>125
</span><span class=lnt>126
</span><span class=lnt>127
</span><span class=lnt>128
</span><span class=lnt>129
</span><span class=lnt>130
</span><span class=lnt>131
</span><span class=lnt>132
</span><span class=lnt>133
</span><span class=lnt>134
</span><span class=lnt>135
</span><span class=lnt>136
</span><span class=lnt>137
</span><span class=lnt>138
</span><span class=lnt>139
</span><span class=lnt>140
</span><span class=lnt>141
</span><span class=lnt>142
</span><span class=lnt>143
</span><span class=lnt>144
</span><span class=lnt>145
</span><span class=lnt>146
</span><span class=lnt>147
</span><span class=lnt>148
</span></code></pre></td><td class=lntd><pre class=chroma><code class=language-js data-lang=js>	<span class=c1>//存放主要交互逻辑的js代码
</span><span class=c1></span>	<span class=c1>// javascript 模块化(package.类.方法)
</span><span class=c1></span>	
	<span class=kd>var</span> <span class=nx>seckill</span> <span class=o>=</span> <span class=p>{</span>
	
	    <span class=c1>//封装秒杀相关ajax的url
</span><span class=c1></span>	    <span class=nx>URL</span><span class=o>:</span> <span class=p>{</span>
	        <span class=nx>now</span><span class=o>:</span> <span class=kd>function</span> <span class=p>()</span> <span class=p>{</span>
	            <span class=k>return</span> <span class=s1>&#39;/seckill/seckill/time/now&#39;</span><span class=p>;</span>
	        <span class=p>},</span>
	        <span class=nx>exposer</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>seckillId</span><span class=p>)</span> <span class=p>{</span>
	            <span class=k>return</span> <span class=s1>&#39;/seckill/seckill/&#39;</span> <span class=o>+</span> <span class=nx>seckillId</span> <span class=o>+</span> <span class=s1>&#39;/exposer&#39;</span><span class=p>;</span>
	        <span class=p>},</span>
	        <span class=nx>execution</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>seckillId</span><span class=p>,</span> <span class=nx>md5</span><span class=p>)</span> <span class=p>{</span>
	            <span class=k>return</span> <span class=s1>&#39;/seckill/seckill/&#39;</span> <span class=o>+</span> <span class=nx>seckillId</span> <span class=o>+</span> <span class=s1>&#39;/&#39;</span> <span class=o>+</span> <span class=nx>md5</span> <span class=o>+</span> <span class=s1>&#39;/execution&#39;</span><span class=p>;</span>
	        <span class=p>}</span>
	    <span class=p>},</span>
	
	    <span class=c1>//验证手机号
</span><span class=c1></span>	    <span class=nx>validatePhone</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>phone</span><span class=p>)</span> <span class=p>{</span>
	        <span class=k>if</span> <span class=p>(</span><span class=nx>phone</span> <span class=o>&amp;&amp;</span> <span class=nx>phone</span><span class=p>.</span><span class=nx>length</span> <span class=o>==</span> <span class=mi>11</span> <span class=o>&amp;&amp;</span> <span class=o>!</span><span class=nb>isNaN</span><span class=p>(</span><span class=nx>phone</span><span class=p>))</span> <span class=p>{</span>
	            <span class=k>return</span> <span class=kc>true</span><span class=p>;</span><span class=c1>//直接判断对象会看对象是否为空,空就是undefine就是false; isNaN 非数字返回true
</span><span class=c1></span>	        <span class=p>}</span> <span class=k>else</span> <span class=p>{</span>
	            <span class=k>return</span> <span class=kc>false</span><span class=p>;</span>
	        <span class=p>}</span>
	    <span class=p>},</span>
	
	    <span class=c1>//详情页秒杀逻辑
</span><span class=c1></span>	    <span class=nx>detail</span><span class=o>:</span> <span class=p>{</span>
	        <span class=c1>//详情页初始化
</span><span class=c1></span>	        <span class=nx>init</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>params</span><span class=p>)</span> <span class=p>{</span>
	            <span class=c1>//手机验证和登录,计时交互
</span><span class=c1></span>	            <span class=c1>//规划我们的交互流程
</span><span class=c1></span>	            <span class=c1>//在cookie中查找手机号
</span><span class=c1></span>	            <span class=kd>var</span> <span class=nx>userPhone</span> <span class=o>=</span> <span class=nx>$</span><span class=p>.</span><span class=nx>cookie</span><span class=p>(</span><span class=s1>&#39;userPhone&#39;</span><span class=p>);</span>
	            <span class=c1>//验证手机号
</span><span class=c1></span>	            <span class=k>if</span> <span class=p>(</span><span class=o>!</span><span class=nx>seckill</span><span class=p>.</span><span class=nx>validatePhone</span><span class=p>(</span><span class=nx>userPhone</span><span class=p>))</span> <span class=p>{</span>
	                <span class=c1>//绑定手机 控制输出
</span><span class=c1></span>	                <span class=kd>var</span> <span class=nx>killPhoneModal</span> <span class=o>=</span> <span class=nx>$</span><span class=p>(</span><span class=s1>&#39;#killPhoneModal&#39;</span><span class=p>);</span>
	                <span class=nx>killPhoneModal</span><span class=p>.</span><span class=nx>modal</span><span class=p>({</span>
	                    <span class=nx>show</span><span class=o>:</span> <span class=kc>true</span><span class=p>,</span><span class=c1>//显示弹出层
</span><span class=c1></span>	                    <span class=nx>backdrop</span><span class=o>:</span> <span class=s1>&#39;static&#39;</span><span class=p>,</span><span class=c1>//禁止位置关闭
</span><span class=c1></span>	                    <span class=nx>keyboard</span><span class=o>:</span> <span class=kc>false</span><span class=c1>//关闭键盘事件
</span><span class=c1></span>	                <span class=p>});</span>
	
	                <span class=nx>$</span><span class=p>(</span><span class=s1>&#39;#killPhoneBtn&#39;</span><span class=p>).</span><span class=nx>click</span><span class=p>(</span><span class=kd>function</span> <span class=p>()</span> <span class=p>{</span>
	                    <span class=kd>var</span> <span class=nx>inputPhone</span> <span class=o>=</span> <span class=nx>$</span><span class=p>(</span><span class=s1>&#39;#killPhoneKey&#39;</span><span class=p>).</span><span class=nx>val</span><span class=p>();</span>
	                    <span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s2>&#34;inputPhone: &#34;</span> <span class=o>+</span> <span class=nx>inputPhone</span><span class=p>);</span>
	                    <span class=k>if</span> <span class=p>(</span><span class=nx>seckill</span><span class=p>.</span><span class=nx>validatePhone</span><span class=p>(</span><span class=nx>inputPhone</span><span class=p>))</span> <span class=p>{</span>
	                        <span class=c1>//电话写入cookie(7天过期)
</span><span class=c1></span>	                        <span class=nx>$</span><span class=p>.</span><span class=nx>cookie</span><span class=p>(</span><span class=s1>&#39;userPhone&#39;</span><span class=p>,</span> <span class=nx>inputPhone</span><span class=p>,</span> <span class=p>{</span><span class=nx>expires</span><span class=o>:</span> <span class=mi>7</span><span class=p>,</span> <span class=nx>path</span><span class=o>:</span> <span class=s1>&#39;/seckill&#39;</span><span class=p>});</span>
	                        <span class=c1>//验证通过　　刷新页面
</span><span class=c1></span>	                        <span class=nb>window</span><span class=p>.</span><span class=nx>location</span><span class=p>.</span><span class=nx>reload</span><span class=p>();</span>
	                    <span class=p>}</span> <span class=k>else</span> <span class=p>{</span>
	                        <span class=c1>//todo 错误文案信息抽取到前端字典里
</span><span class=c1></span>	                        <span class=nx>$</span><span class=p>(</span><span class=s1>&#39;#killPhoneMessage&#39;</span><span class=p>).</span><span class=nx>hide</span><span class=p>().</span><span class=nx>html</span><span class=p>(</span><span class=s1>&#39;&lt;label class=&#34;label label-danger&#34;&gt;手机号错误!&lt;/label&gt;&#39;</span><span class=p>).</span><span class=nx>show</span><span class=p>(</span><span class=mi>300</span><span class=p>);</span>
	                    <span class=p>}</span>
	                <span class=p>});</span>
	            <span class=p>}</span>
	
	            <span class=c1>//已经登录
</span><span class=c1></span>	            <span class=c1>//计时交互
</span><span class=c1></span>	            <span class=kd>var</span> <span class=nx>startTime</span> <span class=o>=</span> <span class=nx>params</span><span class=p>[</span><span class=s1>&#39;startTime&#39;</span><span class=p>];</span>
	            <span class=kd>var</span> <span class=nx>endTime</span> <span class=o>=</span> <span class=nx>params</span><span class=p>[</span><span class=s1>&#39;endTime&#39;</span><span class=p>];</span>
	            <span class=kd>var</span> <span class=nx>seckillId</span> <span class=o>=</span> <span class=nx>params</span><span class=p>[</span><span class=s1>&#39;seckillId&#39;</span><span class=p>];</span>
	            <span class=nx>$</span><span class=p>.</span><span class=nx>get</span><span class=p>(</span><span class=nx>seckill</span><span class=p>.</span><span class=nx>URL</span><span class=p>.</span><span class=nx>now</span><span class=p>(),</span> <span class=p>{},</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>result</span><span class=p>)</span> <span class=p>{</span>
	                <span class=k>if</span> <span class=p>(</span><span class=nx>result</span> <span class=o>&amp;&amp;</span> <span class=nx>result</span><span class=p>[</span><span class=s1>&#39;success&#39;</span><span class=p>])</span> <span class=p>{</span>
	                    <span class=kd>var</span> <span class=nx>nowTime</span> <span class=o>=</span> <span class=nx>result</span><span class=p>[</span><span class=s1>&#39;data&#39;</span><span class=p>];</span>
	                    <span class=c1>//时间判断 计时交互
</span><span class=c1></span>	                    <span class=nx>seckill</span><span class=p>.</span><span class=nx>countDown</span><span class=p>(</span><span class=nx>seckillId</span><span class=p>,</span> <span class=nx>nowTime</span><span class=p>,</span> <span class=nx>startTime</span><span class=p>,</span> <span class=nx>endTime</span><span class=p>);</span>
	                <span class=p>}</span> <span class=k>else</span> <span class=p>{</span>
	                    <span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s1>&#39;result: &#39;</span> <span class=o>+</span> <span class=nx>result</span><span class=p>);</span>
	                    <span class=nx>alert</span><span class=p>(</span><span class=s1>&#39;result: &#39;</span> <span class=o>+</span> <span class=nx>result</span><span class=p>);</span>
	                <span class=p>}</span>
	            <span class=p>});</span>
	        <span class=p>}</span>
	    <span class=p>},</span>
	
	    <span class=nx>handlerSeckill</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>seckillId</span><span class=p>,</span> <span class=nx>node</span><span class=p>)</span> <span class=p>{</span>
	        <span class=c1>//获取秒杀地址,控制显示器,执行秒杀
</span><span class=c1></span>	        <span class=nx>node</span><span class=p>.</span><span class=nx>hide</span><span class=p>().</span><span class=nx>html</span><span class=p>(</span><span class=s1>&#39;&lt;button class=&#34;btn btn-primary btn-lg&#34; id=&#34;killBtn&#34;&gt;开始秒杀&lt;/button&gt;&#39;</span><span class=p>);</span>
	
	        <span class=nx>$</span><span class=p>.</span><span class=nx>get</span><span class=p>(</span><span class=nx>seckill</span><span class=p>.</span><span class=nx>URL</span><span class=p>.</span><span class=nx>exposer</span><span class=p>(</span><span class=nx>seckillId</span><span class=p>),</span> <span class=p>{},</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>result</span><span class=p>)</span> <span class=p>{</span>
	            <span class=c1>//在回调函数种执行交互流程
</span><span class=c1></span>	            <span class=k>if</span> <span class=p>(</span><span class=nx>result</span> <span class=o>&amp;&amp;</span> <span class=nx>result</span><span class=p>[</span><span class=s1>&#39;success&#39;</span><span class=p>])</span> <span class=p>{</span>
	                <span class=kd>var</span> <span class=nx>exposer</span> <span class=o>=</span> <span class=nx>result</span><span class=p>[</span><span class=s1>&#39;data&#39;</span><span class=p>];</span>
	                <span class=k>if</span> <span class=p>(</span><span class=nx>exposer</span><span class=p>[</span><span class=s1>&#39;exposed&#39;</span><span class=p>])</span> <span class=p>{</span>
	                    <span class=c1>//开启秒杀
</span><span class=c1></span>	                    <span class=c1>//获取秒杀地址
</span><span class=c1></span>	                    <span class=kd>var</span> <span class=nx>md5</span> <span class=o>=</span> <span class=nx>exposer</span><span class=p>[</span><span class=s1>&#39;md5&#39;</span><span class=p>];</span>
	                    <span class=kd>var</span> <span class=nx>killUrl</span> <span class=o>=</span> <span class=nx>seckill</span><span class=p>.</span><span class=nx>URL</span><span class=p>.</span><span class=nx>execution</span><span class=p>(</span><span class=nx>seckillId</span><span class=p>,</span> <span class=nx>md5</span><span class=p>);</span>
	                    <span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s2>&#34;killUrl: &#34;</span> <span class=o>+</span> <span class=nx>killUrl</span><span class=p>);</span>
	                    <span class=c1>//绑定一次点击事件
</span><span class=c1></span>	                    <span class=nx>$</span><span class=p>(</span><span class=s1>&#39;#killBtn&#39;</span><span class=p>).</span><span class=nx>one</span><span class=p>(</span><span class=s1>&#39;click&#39;</span><span class=p>,</span> <span class=kd>function</span> <span class=p>()</span> <span class=p>{</span>
	                        <span class=c1>//执行秒杀请求
</span><span class=c1></span>	                        <span class=c1>//1.先禁用按钮
</span><span class=c1></span>	                        <span class=nx>$</span><span class=p>(</span><span class=k>this</span><span class=p>).</span><span class=nx>addClass</span><span class=p>(</span><span class=s1>&#39;disabled&#39;</span><span class=p>);</span><span class=c1>//,&lt;-$(this)===(&#39;#killBtn&#39;)-&gt;
</span><span class=c1></span>	                        <span class=c1>//2.发送秒杀请求执行秒杀
</span><span class=c1></span>	                        <span class=nx>$</span><span class=p>.</span><span class=nx>post</span><span class=p>(</span><span class=nx>killUrl</span><span class=p>,</span> <span class=p>{},</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>result</span><span class=p>)</span> <span class=p>{</span>
	                            <span class=k>if</span> <span class=p>(</span><span class=nx>result</span> <span class=o>&amp;&amp;</span> <span class=nx>result</span><span class=p>[</span><span class=s1>&#39;success&#39;</span><span class=p>])</span> <span class=p>{</span>
	                                <span class=kd>var</span> <span class=nx>killResult</span> <span class=o>=</span> <span class=nx>result</span><span class=p>[</span><span class=s1>&#39;data&#39;</span><span class=p>];</span>
	                                <span class=kd>var</span> <span class=nx>state</span> <span class=o>=</span> <span class=nx>killResult</span><span class=p>[</span><span class=s1>&#39;state&#39;</span><span class=p>];</span>
	                                <span class=kd>var</span> <span class=nx>stateInfo</span> <span class=o>=</span> <span class=nx>killResult</span><span class=p>[</span><span class=s1>&#39;stateInfo&#39;</span><span class=p>];</span>
	                                <span class=c1>//显示秒杀结果
</span><span class=c1></span>	                                <span class=nx>node</span><span class=p>.</span><span class=nx>html</span><span class=p>(</span><span class=s1>&#39;&lt;span class=&#34;label label-success&#34;&gt;&#39;</span> <span class=o>+</span> <span class=nx>stateInfo</span> <span class=o>+</span> <span class=s1>&#39;&lt;/span&gt;&#39;</span><span class=p>);</span>
	                            <span class=p>}</span>
	                        <span class=p>});</span>
	                    <span class=p>});</span>
	                    <span class=nx>node</span><span class=p>.</span><span class=nx>show</span><span class=p>();</span>
	                <span class=p>}</span> <span class=k>else</span> <span class=p>{</span>
	                    <span class=c1>//未开启秒杀(浏览器计时偏差)
</span><span class=c1></span>	                    <span class=kd>var</span> <span class=nx>now</span> <span class=o>=</span> <span class=nx>exposer</span><span class=p>[</span><span class=s1>&#39;now&#39;</span><span class=p>];</span>
	                    <span class=kd>var</span> <span class=nx>start</span> <span class=o>=</span> <span class=nx>exposer</span><span class=p>[</span><span class=s1>&#39;start&#39;</span><span class=p>];</span>
	                    <span class=kd>var</span> <span class=nx>end</span> <span class=o>=</span> <span class=nx>exposer</span><span class=p>[</span><span class=s1>&#39;end&#39;</span><span class=p>];</span>
	                    <span class=nx>seckill</span><span class=p>.</span><span class=nx>countDown</span><span class=p>(</span><span class=nx>seckillId</span><span class=p>,</span> <span class=nx>now</span><span class=p>,</span> <span class=nx>start</span><span class=p>,</span> <span class=nx>end</span><span class=p>);</span>
	                <span class=p>}</span>
	            <span class=p>}</span> <span class=k>else</span> <span class=p>{</span>
	                <span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s1>&#39;result: &#39;</span> <span class=o>+</span> <span class=nx>result</span><span class=p>);</span>
	            <span class=p>}</span>
	        <span class=p>});</span>
	
	    <span class=p>},</span>
	
	    <span class=nx>countDown</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>seckillId</span><span class=p>,</span> <span class=nx>nowTime</span><span class=p>,</span> <span class=nx>startTime</span><span class=p>,</span> <span class=nx>endTime</span><span class=p>)</span> <span class=p>{</span>
	        <span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=nx>seckillId</span> <span class=o>+</span> <span class=s1>&#39;_&#39;</span> <span class=o>+</span> <span class=nx>nowTime</span> <span class=o>+</span> <span class=s1>&#39;_&#39;</span> <span class=o>+</span> <span class=nx>startTime</span> <span class=o>+</span> <span class=s1>&#39;_&#39;</span> <span class=o>+</span> <span class=nx>endTime</span><span class=p>);</span>
	        <span class=kd>var</span> <span class=nx>seckillBox</span> <span class=o>=</span> <span class=nx>$</span><span class=p>(</span><span class=s1>&#39;#seckill-box&#39;</span><span class=p>);</span>
	        <span class=k>if</span> <span class=p>(</span><span class=nx>nowTime</span> <span class=o>&gt;</span> <span class=nx>endTime</span><span class=p>)</span> <span class=p>{</span>
	            <span class=c1>//秒杀结束
</span><span class=c1></span>	            <span class=nx>seckillBox</span><span class=p>.</span><span class=nx>html</span><span class=p>(</span><span class=s1>&#39;秒杀结束!&#39;</span><span class=p>);</span>
	        <span class=p>}</span> <span class=k>else</span> <span class=k>if</span> <span class=p>(</span><span class=nx>nowTime</span> <span class=o>&lt;</span> <span class=nx>startTime</span><span class=p>)</span> <span class=p>{</span>
	            <span class=c1>//秒杀未开始,计时事件绑定
</span><span class=c1></span>	            <span class=kd>var</span> <span class=nx>killTime</span> <span class=o>=</span> <span class=k>new</span> <span class=nb>Date</span><span class=p>(</span><span class=nx>startTime</span> <span class=o>+</span> <span class=mi>1000</span><span class=p>);</span><span class=c1>//todo 防止时间偏移
</span><span class=c1></span>	            <span class=nx>seckillBox</span><span class=p>.</span><span class=nx>countdown</span><span class=p>(</span><span class=nx>killTime</span><span class=p>,</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>event</span><span class=p>)</span> <span class=p>{</span>
	                <span class=c1>//时间格式
</span><span class=c1></span>	                <span class=kd>var</span> <span class=nx>format</span> <span class=o>=</span> <span class=nx>event</span><span class=p>.</span><span class=nx>strftime</span><span class=p>(</span><span class=s1>&#39;秒杀倒计时: %D天 %H时 %M分 %S秒 &#39;</span><span class=p>);</span>
	                <span class=nx>seckillBox</span><span class=p>.</span><span class=nx>html</span><span class=p>(</span><span class=nx>format</span><span class=p>);</span>
	            <span class=p>}).</span><span class=nx>on</span><span class=p>(</span><span class=s1>&#39;finish.countdown&#39;</span><span class=p>,</span> <span class=kd>function</span> <span class=p>()</span> <span class=p>{</span>
	                <span class=c1>//时间完成后回调事件
</span><span class=c1></span>	                <span class=c1>//获取秒杀地址,控制现实逻辑,执行秒杀
</span><span class=c1></span>	                <span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=s1>&#39;______fininsh.countdown&#39;</span><span class=p>);</span>
	                <span class=nx>seckill</span><span class=p>.</span><span class=nx>handlerSeckill</span><span class=p>(</span><span class=nx>seckillId</span><span class=p>,</span> <span class=nx>seckillBox</span><span class=p>);</span>
	            <span class=p>});</span>
	        <span class=p>}</span> <span class=k>else</span> <span class=p>{</span>
	            <span class=c1>//秒杀开始
</span><span class=c1></span>	            <span class=nx>seckill</span><span class=p>.</span><span class=nx>handlerSeckill</span><span class=p>(</span><span class=nx>seckillId</span><span class=p>,</span> <span class=nx>seckillBox</span><span class=p>);</span>
	        <span class=p>}</span>
	    <span class=p>}</span>
	<span class=p>};</span>
</code></pre></td></tr></table></div></div><blockquote><p><strong>脚本文件的技巧</strong></p></blockquote><p>使用Json来讲JavaScript模块化（类似于Java的package），不要将js都写成一堆，不易维护，页不方便阅读。</p><blockquote><p><strong>特殊说明</strong></p></blockquote><p>由于本人的Eclipse内嵌的Tomcat设置的原因，我需要在URL里的所有路径前加上<code>/seckill</code>（我的项目名）才可以正常映射到Controller里对应的方法，如下</p><div class=highlight><div class=chroma><table class=lntable><tr><td class=lntd><pre class=chroma><code><span class=lnt> 1
</span><span class=lnt> 2
</span><span class=lnt> 3
</span><span class=lnt> 4
</span><span class=lnt> 5
</span><span class=lnt> 6
</span><span class=lnt> 7
</span><span class=lnt> 8
</span><span class=lnt> 9
</span><span class=lnt>10
</span><span class=lnt>11
</span><span class=lnt>12
</span></code></pre></td><td class=lntd><pre class=chroma><code class=language-js data-lang=js>	<span class=c1>//封装秒杀相关ajax的url
</span><span class=c1></span>    <span class=nx>URL</span><span class=o>:</span> <span class=p>{</span>
        <span class=nx>now</span><span class=o>:</span> <span class=kd>function</span> <span class=p>()</span> <span class=p>{</span>
            <span class=k>return</span> <span class=s1>&#39;/seckill/seckill/time/now&#39;</span><span class=p>;</span>
        <span class=p>},</span>
        <span class=nx>exposer</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>seckillId</span><span class=p>)</span> <span class=p>{</span>
            <span class=k>return</span> <span class=s1>&#39;/seckill/seckill/&#39;</span> <span class=o>+</span> <span class=nx>seckillId</span> <span class=o>+</span> <span class=s1>&#39;/exposer&#39;</span><span class=p>;</span>
        <span class=p>},</span>
        <span class=nx>execution</span><span class=o>:</span> <span class=kd>function</span> <span class=p>(</span><span class=nx>seckillId</span><span class=p>,</span> <span class=nx>md5</span><span class=p>)</span> <span class=p>{</span>
            <span class=k>return</span> <span class=s1>&#39;/seckill/seckill/&#39;</span> <span class=o>+</span> <span class=nx>seckillId</span> <span class=o>+</span> <span class=s1>&#39;/&#39;</span> <span class=o>+</span> <span class=nx>md5</span> <span class=o>+</span> <span class=s1>&#39;/execution&#39;</span><span class=p>;</span>
        <span class=p>}</span>
    <span class=p>},</span>
</code></pre></td></tr></table></div></div><p>如果有同学在后边测试页面时找不到路径，可以将这里的路径里的<code>/seckill</code>删掉</p><h3 id=42-编写页面><strong>4.2 编写页面</strong></h3><p>在<code>WEB-INF</code>目录下新建一个<code>jsp</code>目录，在这里存放我们的jsp页面，为了减少工作量，也为了方便，将每个页面都会使用到的头部文件和标签库分离出来，放到<code>common</code>目录下，在jsp页面中静态包含这两个公共页面就行了。</p><p>关于jsp页面请从源码中拷贝，实际开发中前端页面由前端工程师完成，但是后端工程师也应该了解jQuery和ajax，想要了解本项目的页面是如何实现的请观看慕课网的<a href=http://www.imooc.com/learn/630 target=_blank rel="noopener noreffer">Java高并发秒杀API之Web层</a>。</p><blockquote><p><strong>静态包含和动态包含的区别</strong></p></blockquote><p>静态包含会直接将页面包含进来，最终只生成一个Servlet；而动态包含会先将要包含进来的页面生成Servlet后再包含进来，最终会生成多个Servlet。</p><blockquote><p><strong>存在的坑</strong></p></blockquote><p>在页面里不要写成<code>&lt;script/></code>，这样写会导致后边的js加载不了，所以要写成<code>&lt;script>&lt;/script></code>。</p><blockquote><p><strong>EL表达式</strong></p></blockquote><p>startTime是Date类型的，通过<code>${startTime.time}</code>来将Date转换成long类型的毫秒值。</p><h3 id=43-测试页面><strong>4.3 测试页面</strong></h3><p>先clean下Maven项目，接着编译Maven项目（<code>-X compile</code>命令），然后启动Tomcat，在浏览器输入<code>http://localhost:8080/seckill/seckill/list</code>，成功进入秒杀商品页面；输入<code>http://localhost:8080/seckill/seckill/1000/detail</code>成功进入详情页面。</p><blockquote><p><strong>配置使用jquery countdown插件</strong></p></blockquote><p>1.pom.xml</p><div class=highlight><div class=chroma><table class=lntable><tr><td class=lntd><pre class=chroma><code><span class=lnt>1
</span><span class=lnt>2
</span><span class=lnt>3
</span><span class=lnt>4
</span><span class=lnt>5
</span><span class=lnt>6
</span><span class=lnt>7
</span><span class=lnt>8
</span><span class=lnt>9
</span></code></pre></td><td class=lntd><pre class=chroma><code class=language-xml data-lang=xml>	<span class=nt>&lt;dependency&gt;</span>
	
	  <span class=nt>&lt;groupId&gt;</span>org.webjars.bower<span class=nt>&lt;/groupId&gt;</span>
	
	  <span class=nt>&lt;artifactId&gt;</span>jquery.countdown<span class=nt>&lt;/artifactId&gt;</span>
	
	  <span class=nt>&lt;version&gt;</span>2.1.0<span class=nt>&lt;/version&gt;</span>
	
	 <span class=nt>&lt;/dependency&gt;</span>
</code></pre></td></tr></table></div></div><p>2.页面</p><div class=highlight><div class=chroma><table class=lntable><tr><td class=lntd><pre class=chroma><code><span class=lnt>1
</span></code></pre></td><td class=lntd><pre class=chroma><code class=language-js data-lang=js>	   <span class=o>&lt;</span><span class=nx>script</span> <span class=nx>src</span><span class=o>=</span><span class=s2>&#34;${pageContext.request.contextPath}/webjars/jquery.countdown/2.1.0/dist/jquery.countdown.min.js&#34;</span><span class=o>&gt;&lt;</span><span class=err>/script&gt;</span>
</code></pre></td></tr></table></div></div><blockquote><p><strong>其他问题</strong></p></blockquote><p>关于显示<code>NaN天 NaN时 NaN分 NaN秒</code>的问题，原因是new Date(startTime + 1000)，startTime 被解释成一个字符串了。</p><p>解决办法：</p><ol><li>new Date(startTime-0 + 1000);</li><li>new Date(Number(startTime) + 1000);</li></ol><blockquote><p><strong>关于分布式环境下的几个问题以及慕课网张老师的回答</strong></p></blockquote><ul><li>根据系统标准时间判断，如果分布式环境下各机器时间不同步怎么办？同时发起的两次请求，可能一个活动开始，另一个提示没开始。</li></ul><p>后端服务器需要做NTP时间同步，如每5分钟与NTP服务同步保证时间误差在微妙级以下。时间同步在业务需要或者活性检查场景很常见(如hbase的RegionServer)</p><ul><li>如果判断逻辑都放到后端，遇到有刷子，后端处理这些请求扛不住了怎么办？可能活动没开始，服务器已经挂掉了。</li></ul><p>秒杀开启判断在前端和后端都有，后端的判断比较简单取秒杀单做判断，这块的IO请求是DB主键查询很快，单DB就可以抗住几万QPS,后面也会加入redis缓存为DB减负。</p><ul><li>负载均衡问题，比如根据地域在nginx哈希，怎样能较好的保证各机器秒杀成功的尽量分布均匀呢。</li></ul><p>负载均衡包括nginx入口端和后端upstream服务，在入口端一般采用智能DNS解析请求就近进入nginx服务器。后端upstgream不建议采用一致性hash，防止请求不均匀。后端服务无状态可以简单使用轮训机制。nginx负载均衡本身过于简单，可以使用openresty自己实现或者nginx之后单独架设负载均衡服务如Netflix的Zuul等。</p><p>对于流量爆增的造成后端不可用情况，这门课程(Java高并发秒杀API)并没有做动态降级和弹性伸缩架构上的处理，后面受慕课邀请会做一个独立的实战课，讲解分布式架构，弹性容错，微服务相关的内容，到时会加入这方面的内容。</p><blockquote><p><strong>本节结语</strong></p></blockquote><p>至此，关于Java高并发秒杀API的Web层的开发与测试已经完成，接下来进行对该秒杀系统进行高并发优化，详情可以参考下一篇文章。</p><p>上一篇文章：<a href=http://blog.csdn.net/lewky_liu/article/details/78162149 target=_blank rel="noopener noreffer"><strong>Java高并发秒杀API(二)之Service层</strong></a></p><p>下一篇文章：<a href=http://blog.csdn.net/lewky_liu/article/details/78166080 target=_blank rel="noopener noreffer"><strong>Java高并发秒杀API(四)之高并发优化</strong></a></p><div class="details admonition warning open"><div class="details-summary admonition-title"><i class="icon fas fa-exclamation-triangle fa-fwwarning"></i>警告<i class="details-icon fas fa-angle-right fa-fw"></i></div><div class=details-content><div class=admonition-content>本文最后更新于 <span class=timeago datetime=2017-10-05T18:03:54 title="October 5, 2017">October 5, 2017</span>，文中内容可能已过时，请谨慎使用。</div></div></div><div class=post-reward><input type=checkbox name=reward id=reward hidden>
<label class=reward-button for=reward>赞赏支持</label><div class=qr-code><label class=qr-code-image for=reward><img class=image src=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/common/wechat.png>
<span>微信打赏</span></label>
<label class=qr-code-image for=reward><img class=image src=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/common/alipay.png>
<span>支付宝打赏</span></label></div></div></div><div class=post-footer id=post-footer><div class=post-info><div class=post-info-line><div class=post-info-mod><span>更新于 2017-10-05</span></div><div class=post-info-license><span><a rel="license external nofollow noopener noreffer" href=https://creativecommons.org/licenses/by-nc/4.0/ target=_blank>CC BY-NC 4.0</a></span></div></div><div class=post-info-line><div class=post-info-md><span><a class=link-to-markdown href=/posts/33818.html/index.md target=_blank>阅读原始文档</a></span></div><div class=post-info-share><span><a href=javascript:void(0); title="分享到 Twitter" data-sharer=twitter data-url=https://lewky.cn/posts/33818.html/ data-title=Java高并发秒杀API(三)之Web层 data-hashtags=项目笔记,SSM实战项目,秒杀><i class="fab fa-twitter fa-fw"></i></a><a href=javascript:void(0); title="分享到 Facebook" data-sharer=facebook data-url=https://lewky.cn/posts/33818.html/ data-hashtag=项目笔记><i class="fab fa-facebook-square fa-fw"></i></a><a href=javascript:void(0); title="分享到 Hacker News" data-sharer=hackernews data-url=https://lewky.cn/posts/33818.html/ data-title=Java高并发秒杀API(三)之Web层><i class="fab fa-hacker-news fa-fw"></i></a><a href=javascript:void(0); title="分享到 Line" data-sharer=line data-url=https://lewky.cn/posts/33818.html/ data-title=Java高并发秒杀API(三)之Web层><i data-svg-src=https://cdn.jsdelivr.net/npm/simple-icons@2.14.0/icons/line.svg></i></a><a href=javascript:void(0); title="分享到 微博" data-sharer=weibo data-url=https://lewky.cn/posts/33818.html/ data-title=Java高并发秒杀API(三)之Web层><i class="fab fa-weibo fa-fw"></i></a></span></div></div></div><div class=post-info-more><section class=post-tags><i class="fas fa-tags fa-fw"></i>&nbsp;<a href=/tags/%E9%A1%B9%E7%9B%AE%E7%AC%94%E8%AE%B0/>项目笔记</a>,&nbsp;<a href=/tags/ssm%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/>SSM实战项目</a>,&nbsp;<a href=/tags/%E7%A7%92%E6%9D%80/>秒杀</a></section><section><span><a href=javascript:void(0); onclick=window.history.back();>返回</a></span>&nbsp;|&nbsp;<span><a href=/>主页</a></span></section></div><div class=post-nav><a href=/posts/18357.html/ class=prev rel=prev title=Java高并发秒杀API(二)之Service层><i class="fas fa-angle-left fa-fw"></i>Java高并发秒杀API(二)之Service层</a>
<a href=/posts/43941.html/ class=next rel=next title=Java高并发秒杀API(四)之高并发优化>Java高并发秒杀API(四)之高并发优化<i class="fas fa-angle-right fa-fw"></i></a></div></div><div id=comments><div id=waline></div><script src=https://cdn.jsdelivr.net/npm/@waline/client/dist/Waline.min.js></script><script>new Waline({el:'#waline',meta:["nick","mail","link"],requiredMeta:["nick","mail"],login:"force",placeholder:"为防恶意灌水攻击，评论前需注册并登录，望见谅~",serverURL:"https://comment.lewky.cn/",avatarCDN:"https://sdn.geekzu.org/avatar/",pageSize:20,avatar:"retro",lang:"zh-CN",visitor:true,highlight:true,uploadImage:false,emoji:['https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/emoji/嘉然今天吃什么','https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/emoji/大航海嘉然','https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/emoji/向晚大魔王','https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/emoji/贝拉kira','https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/emoji/珈乐Carol','https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/emoji/乃琳Queen','https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/emoji/EveOneCat','https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/weibo','https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/emoji/滑稽','https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/emoji/default']});</script></div></article></div></main><footer class=footer><div class=footer-container><div class=footer-line><span id=run-time></span>|
<a href=http://rssblog.vercel.app/ target=_blank rel=noopener title=RSSBlog><i class="fas fa-fw fa-inbox"></i>&nbsp;RSSBlog</a></div><div class=footer-line><i class="far fa-copyright fa-fw"></i><span itemprop=copyrightYear>2018 - 2022</span><span class=author itemprop=copyrightHolder>&nbsp;<a href=/ target=_blank>雨临Lewis</a></span>&nbsp;|&nbsp;<span class=license><a rel="license external nofollow noopener noreffer" href=https://creativecommons.org/licenses/by-nc/4.0/ target=_blank>CC BY-NC 4.0</a></span><span class=icp-splitter>&nbsp;|&nbsp;</span><br class=icp-br><span class=icp><a target=_blank href=http://www.beian.miit.gov.cn/ style=font-weight:700>粤ICP备19103822</a></span></div></div></footer></div><div id=fixed-buttons><a href=# id=back-to-top class=fixed-button title=回到顶部><i class="fas fa-arrow-up fa-fw"></i></a><a href=# id=view-comments class=fixed-button title=查看评论><i class="fas fa-comment fa-fw"></i></a></div><div class=sidebar_wo><div id=leimu><img src=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/b2t/leimuA.png alt=雷姆 onmouseover="this.src='https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/b2t/leimuB.png'" onmouseout="this.src='https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/b2t/leimuA.png'" title=回到顶部></div><div class=sidebar_wo id=lamu><img src=https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master/images/b2t/lamuA.png alt=雷姆 onmouseover="this.src='https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/b2t/lamuB.png'" onmouseout="this.src='https:\/\/cdn.jsdelivr.net\/gh\/lewky\/lewky.github.io@master/images/b2t/lamuA.png'" title=回到底部></div></div><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/lightgallery.js@1.2.0/dist/css/lightgallery.min.css><script type=text/javascript src=https://cdn.jsdelivr.net/npm/smooth-scroll@16.1.3/dist/smooth-scroll.min.js></script><script type=text/javascript src=https://cdn.jsdelivr.net/npm/lazysizes@5.2.2/lazysizes.min.js></script><script type=text/javascript src=https://cdn.jsdelivr.net/npm/lightgallery.js@1.2.0/dist/js/lightgallery.min.js></script><script type=text/javascript src=https://cdn.jsdelivr.net/npm/lg-thumbnail.js@1.2.0/dist/lg-thumbnail.min.js></script><script type=text/javascript src=https://cdn.jsdelivr.net/npm/lg-zoom.js@1.2.0/dist/lg-zoom.min.js></script><script type=text/javascript src=https://cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js></script><script type=text/javascript src=https://cdn.jsdelivr.net/npm/sharer.js@0.4.0/sharer.min.js></script><script type=text/javascript>window.config={"code":{"copyTitle":"复制到剪贴板","maxShownLines":30},"comment":{},"lightGallery":{"actualSize":false,"exThumbImage":"data-thumbnail","hideBarsDelay":2000,"selector":".lightgallery","speed":400,"thumbContHeight":80,"thumbWidth":80,"thumbnail":true}};</script><script type=text/javascript src=/js/theme.min.js></script><script type=text/javascript src=https://cdn.jsdelivr.net/npm/jquery@2.1.3/dist/jquery.min.js></script><script type=text/javascript src=https://cdn.jsdelivr.net/npm/jquery-backstretch@2.1.18/jquery.backstretch.min.js></script><script>var $cdnPrefix="https://cdn.jsdelivr.net/gh/lewky/lewky.github.io@master";</script><script type=text/javascript src=/js/custom.js></script><script>var _hmt=_hmt||[];(function(){var hm=document.createElement("script");hm.src="https://hm.baidu.com/hm.js?6f278ed0fdb01edb3b1e7398379e5432";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm,s);})();</script></body></html>